iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
1
Modern Web

Angular新手村學習筆記(2019)系列 第 16

Day16_ATDD測試觀念及手法

  • 分享至 

  • xImage
  •  

我們只看測試,所以[S03E03] ngx-translate就跳過去囉
https://www.youtube.com/watch?v=l_eA6ti41ww&list=PL9LUW6O9WZqgUMHwDsKQf3prtqVvjGZ6S&index=41
ngx-translate在2019年的Angular Taiwan社群小聚有再分享,請參考Neil Sie大大的影片
https://www.facebook.com/ming.little.14/videos/2563679736986300/

  • 延伸閱讀
  1. 中文的angular文件的testing
    https://angular.tw/guide/testing
  2. 一次搞懂單元測試、整合測試、端對端測試之間的差異
    Will保哥的文章
    https://blog.miniasp.com/post/2019/02/18/Unit-testing-Integration-testing-e2e-testing
  3. Angular測試筆記
    cloverhsc的blog
    https://cloverhsc.blogspot.com/2018/12/angular-testing-2-jasmine.html?view=flipcard
    今天主要看 由 SAM 大大分享精彩的
    [S03E04] ATDD 測試觀念及手法
    https://www.youtube.com/watch?v=6PXapFk3qEg&list=PL9LUW6O9WZqgUMHwDsKQf3prtqVvjGZ6S&index=40

所有程式碼都寫在
https://github.com/oomusou/NG43ATDDSelect
文章在dropbox
https://paper.dropbox.com/doc/Event-Binding-22-3I4TFShvLoxwwxtPSH9s0

由於SAM大大的文章寫得很清楚了,我沒必要再加註解了(畫蛇添足),很建議大家閱讀

我覺得e2e比單元測試難多了,因為要能把使用者用瀏覽器操作的行為,用程式碼寫出來
1、用selector找到element
2、操作element,例如:click(),模擬使用者點了一下
3、如果api是return promise物件,可能還要用await、async去等

TDD Life Cycle

        驗收測試                  整合測試                 單元測試
Acceptance Test Failed -> Integration Test Failed -> Unit Test Failed
            ^                                               |
            |Refactoring                                    V
Acceptance Test Passed <- Integration Test Passed <- Unit Test Passed

使用到的Library

Protractor
Jasmine
Karma

Wallaby.js,可以即時看紅燈、綠燈(要錢的),我也沒買
延伸閱讀:
https://dotblogs.com.tw/technicaldebt/2017/12/25/104427
https://poychang.github.io/wallaby-js-advanced-logging/

SAM大大會從
驗收測試(紅燈)->整合測試(紅燈)->單元測試(紅燈)
再從
單元測試(綠燈)->…寫回驗收測試(綠燈)

整段用簡單的下拉式選單,來示範ATTD,配合著dropbox的文章看很好理解

驗收測試(紅燈)

  • 測試案例
  1. 下拉選單應該有 3 個選項
  2. 選擇 AWS 時,下方應該出現 0
  3. 選擇 Azure 時,下方應該出現 1
  4. 選擇 Aliyun 時,下方應該出現 2
e2e/ // 驗收測試 寫在專案的這個目錄
    app.e2e-spec.ts // 寫測試案例的地方
    app.po.ts // 把css跟測試案例解耦合
    tsconfig.e2e.json // 設定使用的測試框架
  1. 先在app.e2e-spec.ts寫測試案例
  2. 在app.po.ts把app.e2e-spec.ts要用到對HTML的操作寫成function

整合測試(紅燈)

  • 整合測試 在驗證template(html)的各種binding(data binding、event binding、property binding)

  • 整合測試、單元測試都寫在/src/app/底下的各components的spec.ts檔裡
    /src/app/app.component.spec.ts

  • 測試案例

  1. 觸發 <select>change event,應該呼叫 onChange()
  2. 應該使用 selectedId field
    describe(`Integration Test`, () => {
      it(`should use 'onChange()' on 'change' event in HTML`, () => {
        spyOn(component, 'onChange');

        debugElement.query(By.css('#TDDSelect')).triggerEventHandler('change', null);
        expect(component.onChange).toHaveBeenCalled();
      });

      it(`should use 'selectedId' in HTML`, () => {
        component.selectedId = '0';
        ^^^^^^^^整合測試用component
        htmlElement = debugElement.query(By.css('p')).nativeElement;
        expect(htmlElement.textContent).toBe('0');
      });
    });

單元測試(紅燈)

  • 測class

  • 一樣寫在/src/app/底下的各components的spec.ts檔裡,但至少要另外寫一個describe(),目的不同

  • 把class跟template(html)binding分開,以後重構class,才不會跟template有牽連
    /src/app/app.component.spec.ts

  • 測試案例

  1. 應該有 onChange()使 selectedId field 根據參數值改變

在寫單元測試的時候,就要想class要怎麼寫了

    describe(`Unit Test`, () => {
      it(`should have 'onChange()' to make 'selectedId' as selected value in Class`, () => {
        const stub = <HTMLSelectElement>                  {'value': '1'};
                       ^^^^Object轉型為HTMLSelectElement    ^^^^^^先塞假資料
        target.onChange(stub); // onChange還沒實作,目前還是(紅燈)
        ^^^^^ 單元測試在用的變數
        expect(target.selectedId).toBe('1');
      });

上面測試案例都寫完之後,再來就是從單元測試開始依照測試案例開始實作

當測試寫完後,感覺實作會更明確,更快。
當然這只是一個下拉式選單,如果頁面較複雜不知道會怎麼樣
不過實測試能寫到什麼程度,就測到

單元測試(綠燈)

實作class(app.component.ts)

整合測試(綠燈)

實作template(html)上的各種binding

以上就實作完了

驗收測試(綠燈)

模擬使用者對瀏覽器的操作

重構

例如:

  1. 把偷吃步的語法改用更嚴僅的語法
  2. 把寫死的地方改寫
    原本select寫死只有3項,變成用*ngFor

寫測試的好處

  • 多花時間寫測試比較辛苦(約多10%~20%),但後期可安心重構
  • 若改完程式,測試通過,但程式還是出問題,就是測試涵蓋率不足
  • 從整合測試開始寫,完全符合使用者需求
    單元測試、整合測試怎麼寫使用者不會管,但驗收測試與使用者需求相關
    從單元測試開始寫,會與使用者需求缺一部分,這部分要另外彌補

先寫完整合測試(畫面要看到什麼、當使用者的操作時會有什麼結果…)
再拆解成整合測試,單元測試

  • 當程式寫完後,就不會想去補驗收測試。但先寫驗收測試,就會逼自己把測試寫完再寫程式

Q&A

  • 使用者一直改需求,測試不是也要改?
    沒導入測試,手動測試更花時間 > 修改測試案例的時間
    有測試,可減少開瀏覽器測試的時間,專心coding
    (排版還是得開瀏覽器、功能面就不需要開瀏覽器)

  • 用Reactive Form會比較好寫測試

  • e2e的驗收測試不難寫,難在怎麼用selector找到要抓element

  • 單元測試也不難寫,只是測class裡的function、變數

  • 整合測試較難寫,測html各種binding,比較不直覺。需要獨特技巧
    官網docs的testing要看細一點,內含需多測試技巧(但只適用Angular)
    https://angular.io/guide/testing

  • TestBed()已幫我們降低「component跟html的關係」的難度

  • 整合測試需要fixture.detectChanges(),但單元測試不用
    整合測試需要把model更新到view


上一篇
Day15_Jasmine&Protractor
下一篇
Day17_[S03E05、06、07,S04E06]其他測試QQ(沒寫筆記)
系列文
Angular新手村學習筆記(2019)33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言